
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>

#include "qlist.h"

static int filled_node(QNode *new_node, void *data, size_t data_len);

QNode *create_node(void *data, size_t data_len)
{
    /* check the input parameter data_len */ 
    if(data_len > DATA_SIZE)
    {
        fprintf(stderr, "data_len is too large\n");
        return NULL;
    }

    // Create a new node with the given data
    QNode *node = (QNode *)malloc(sizeof(QNode));
    if (!node)
    {
        perror("node malloc failed");
        exit(EXIT_FAILURE);
    }
    /* malloc for data member */ 
    node->data = malloc(DATA_SIZE);
    if (!node->data)
    {
        perror("node->data malloc failed");
        free(node);
        exit(EXIT_FAILURE);
    }

    /* copy data to node->data member */ 
    if (data != NULL)
    {
        memcpy(node->data, data, data_len);
        char *str_data = (char *)node->data;
        printf("create_node data: %s\n", str_data);
    }
    else
    {
        /* do nothing */
    }

    node->data_len = data_len;
    node->next = NULL;

    return node;
}

void insert_head(QNode **head, void *data, size_t data_len)
{
    QNode *node = create_node(data, data_len);
    node->data_len = data_len;
    node->next = *head;
    *head = node;
}

void insert_node_to_head(QNode **head, QNode *new_node, void *data, size_t data_len)
{
    if (new_node == NULL)
        return;

    filled_node(new_node, data, data_len);

    new_node->next = *head;
    *head = new_node;
}

static int filled_node(QNode *new_node, void *data, size_t data_len)
{
    int ret = 0;
    
    memset(new_node->data, 0, DATA_SIZE);
    memcpy(new_node->data, data, data_len);
    char *str_data = (char *)new_node->data;
    printf("create_node data: %s\n", str_data);
    new_node->data_len = data_len;
    new_node->next = NULL;

    return OK_NO;
}

void insert_tail(QNode **head, void *data, size_t data_len)
{
    QNode *node = create_node(data, data_len);
    if (*head == NULL)
    {
        *head = node;
        return;
    }
    QNode *curr = *head;
    while (curr->next != NULL)
        curr = curr->next;
    curr->next = node;
}

void insert_node_to_tail(QNode **head, QNode *new_node, void *data, size_t data_len)
{
    if (new_node == NULL)
        return;

    filled_node(new_node, data, data_len);

    if (*head == NULL)
    {
        *head = new_node;
        return;
    }
    QNode *curr = *head;
    while (curr->next != NULL)
        curr = curr->next;
    curr->next = new_node;
}

void delete_node(QNode **head, void *key, int (*cmp)(void *, void *), void (*free_func)(void *))
{
    QNode *curr = *head;
    QNode *prev = NULL;

    while (curr)
    {
        if (cmp(curr->data, key) == 0)
        {
            if (prev == NULL)
            {
                *head = curr->next;
            }
            else
            {
                prev->next = curr->next;
            }
            if (free_func)
                free_func(curr->data);
            free(curr);
            return;
        }
        prev = curr;
        curr = curr->next;
    }
}

QNode *find_node(QNode *head, void *key, int (*cmp)(void *, void *))
{
    QNode *curr = head;
    while (curr)
    {
        if (cmp(curr->data, key) == 0)
            return curr;
        curr = curr->next;
    }
    return NULL;
}

QNode *pick_tail_node(QNode **head, int must_has_data_flag)
{
    QNode *curr = *head;
    QNode *pre = NULL;
    /* just left the head node, no data, return NULL */
    if (must_has_data_flag && curr->data == NULL)
    {
        return NULL;
    }

    while (curr && curr->next && curr->next->data)
    {
        pre = curr;
        curr = curr->next;
    }
    /* pre has value means has node to consume */
    if (pre)
    {
        pre->next = curr->next;
    }
    /* no sub node, return self */
    else
    {
        *head = curr->next;
    }

    return curr;
}

void print_list(QNode *head, void (*print_func)(QNode *))
{
    QNode *curr = head;
    while (curr)
    {
        if (curr->data == NULL)
        {
            printf("data is NULL\n");
            break;
        }
        else
        {
            print_func(curr);
        }
        curr = curr->next;
    }
}

void free_list(QNode *head, void (*free_func)(void *))
{
    QNode *curr = head;
    while (curr)
    {
        QNode *next = curr->next;
        if (free_func)
            free_func(curr->data);
        free(curr);
        curr = next;
    }
}

void free_node_data(void *data)
{
    char *s = (char *)data;
    free(s);
}

int list_node_count(QNode *head)
{
    int count = 0;
    if (head == NULL)
        return count;

    QNode *curr = head->next;
    while (curr)
    {
        count++;
        curr = curr->next;
    }

    return count;
}